home *** CD-ROM | disk | FTP | other *** search
/ The CICA Windows Explosion! / The CICA Windows Explosion! - Disc 2.iso / programr / eckelt01.zip / 10 / RCTRACE.CPP < prev    next >
C/C++ Source or Header  |  1995-02-23  |  5KB  |  156 lines

  1. // File from page 440 in "Thinking in C++" by Bruce Eckel
  2. //////////////////////////////////////////////////
  3. // From the compressed package ECKELT01.ZIP 2/21/95
  4. // Copyright (c) Bruce Eckel, 1995 
  5. // Source code file from the book "Thinking in C++", 
  6. // Prentice Hall, 1995, ISBN: 0-13-917709-4
  7. // All rights reserved EXCEPT as allowed by the following 
  8. // statements: You may freely use this file for your own 
  9. // work, including modifications and distribution in 
  10. // executable form only. You may copy and distribute this 
  11. // file, as long as it is only distributed in the complete 
  12. // (compressed) package with the other files from this 
  13. // book and you do not remove this copyright and notice. 
  14. // You may not distribute modified versions of the source 
  15. // code in this package. This package may be freely placed 
  16. // on bulletin boards, internet nodes, shareware disks and 
  17. // product vendor disks. You may not use this file in 
  18. // printed media without the express permission of the 
  19. // author. Bruce Eckel makes no 
  20. // representation about the suitability of this software 
  21. // for any purpose. It is provided "as is" without express 
  22. // or implied warranty of any kind. The entire risk as to 
  23. // the quality and performance of the software is with 
  24. // you. Should the software prove defective, you assume 
  25. // the cost of all necessary servicing, repair, or 
  26. // correction. 
  27. // If you think you've found an error, please 
  28. // email all modified files with loudly commented changes 
  29. // to: eckel@aol.com (please use the same 
  30. // address for non-code errors found in the book).
  31. //////////////////////////////////////////////////
  32.  
  33. //: RCTRACE.CPP -- REFCOUNT.CPP w/ trace info
  34. #include <string.h>
  35. #include <fstream.h>
  36. #include <assert.h>
  37. ofstream out("rctrace.out");
  38.  
  39. class counted {
  40.   class memblock {
  41.     enum { size = 100 };
  42.     char c[size];
  43.     int refcount;
  44.     static int blockcount;
  45.     int blocknum;
  46.   public:
  47.     memblock() {
  48.       memset(c, 1, size);
  49.       refcount = 1;
  50.       blocknum = blockcount++;
  51.     }
  52.     memblock(const memblock& rv) {
  53.       memcpy(c, rv.c, size);
  54.       refcount = 1;
  55.       blocknum = blockcount++;
  56.       print("copied block");
  57.       out << endl;
  58.       rv.print("from block");
  59.     }
  60.     ~memblock() {
  61.       out << "\tdestroying block "
  62.           << blocknum << endl;
  63.     }
  64.     void print(const char* msg = "") const {
  65.       if(*msg) out << msg << ", ";
  66.       out << "blocknum:" << blocknum;
  67.       out << ", refcount:" << refcount;
  68.     }
  69.     void attach() { ++refcount; }
  70.     void detach() {
  71.       assert(refcount != 0);
  72.       // Destroy object if no one is using it:
  73.       if(--refcount == 0) delete this;
  74.     }
  75.     int count() const { return refcount; }
  76.     void set(char x) { memset(c, x, size); }
  77.     // Conditionally copy this memblock.
  78.     // Call before modifying the block; assign
  79.     // resulting pointer to your block;
  80.     memblock* unalias() {
  81.       // Don't duplicate if not aliased:
  82.       if(refcount == 1) return this;
  83.       --refcount;
  84.       // Use copy-constructor to duplicate:
  85.       return new memblock(*this);
  86.     }
  87.   } * block;
  88.   enum { sz = 30 };
  89.   char id[sz];
  90. public:
  91.   counted(const char* ID = "tmp") {
  92.     block = new memblock; // Sneak preview
  93.     strncpy(id, ID, sz);
  94.   }
  95.   counted(const counted& rv) {
  96.     block = rv.block; // Pointer assignment
  97.     block->attach();
  98.     strncpy(id, rv.id, sz);
  99.     strncat(id, " copy", sz - strlen(id));
  100.   }
  101.   void unalias() { block = block->unalias(); }
  102.   void addname(const char* nm) {
  103.     strncat(id, nm, sz - strlen(id));
  104.   }
  105.   counted& operator=(const counted& rv) {
  106.     print("inside operator=\n\t");
  107.     if(&rv == this) {
  108.       out << "self-assignment" << endl;
  109.       return *this;
  110.     }
  111.     // Clean up what you're using first:
  112.     block->detach();
  113.     block = rv.block; // Like copy-constructor
  114.     block->attach();
  115.     return *this;
  116.   }
  117.   // Decrement refcount, conditionally destroy
  118.   ~counted() {
  119.     out << "preparing to destroy: " << id
  120.         << endl << "\tdecrementing refcount ";
  121.     block->print();
  122.     out << endl;
  123.     block->detach();
  124.   }
  125.   // Copy-on-write:
  126.   void write(char value) {
  127.     unalias();
  128.     block->set(value);
  129.   }
  130.   void print(const char* msg = "") {
  131.     if(*msg) out << msg << " ";
  132.     out << "object " << id << ": ";
  133.     block->print();
  134.     out << endl;
  135.   }
  136. };
  137.  
  138. int counted::memblock::blockcount = 0;
  139.  
  140. main() {
  141.   counted A("A"), B("B");
  142.   counted C(A);
  143.   C.addname(" (C) ");
  144.   A.print();
  145.   B.print();
  146.   C.print();
  147.   B = A;
  148.   A.print("after assignment\n\t");
  149.   B.print();
  150.   out << "Assigning C = C" << endl;
  151.   C = C;
  152.   C.print("calling C.write('x')\n\t");
  153.   C.write('x');
  154.   out << endl << "exiting main()" << endl;
  155. }
  156.